home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / MNetsrc.hqx / Mac TCP_IP Source v.33 / smtpserv.c < prev    next >
Text File  |  1989-02-24  |  18KB  |  828 lines

  1. /* SMTP Server state machine - see RFC 821
  2.  *  enhanced 4/88 Dave Trulli nn2z
  3.  */
  4. #include <stdio.h>
  5. #include "global.h"
  6. #include <time.h>
  7. #ifdef MAC
  8. #include <types.h>
  9. #endif
  10. #ifdef UNIX
  11. #include <sys/types.h>
  12. #endif
  13. #include <ctype.h>
  14. #include "mbuf.h"
  15. #include "netuser.h"
  16. #include "timer.h"
  17. #include "tcp.h"
  18. #include "smtp.h"
  19.  
  20. char *getname();
  21. void mail_delete();
  22. #ifdef MAC
  23. int rqueuejob();
  24. #else
  25. static int rqueuejob();
  26. #endif
  27. int queuejob();
  28. int validate_address();
  29. long get_msgid();
  30. struct list *addlist();
  31. struct list * expandalias();
  32.  
  33. /* Command table */
  34. static char *commands[] = {
  35.     "helo",
  36. #define    HELO_CMD    0
  37.     "noop",
  38. #define    NOOP_CMD    1
  39.     "mail from:",
  40. #define    MAIL_CMD    2
  41.     "quit",
  42. #define    QUIT_CMD    3
  43.     "rcpt to:",
  44. #define    RCPT_CMD    4
  45.     "help",
  46. #define    HELP_CMD    5
  47.     "data",
  48. #define    DATA_CMD    6
  49.     "rset",
  50. #define    RSET_CMD    7
  51.     NULLCHAR
  52. };
  53.  
  54. /* Reply messages */
  55. static char help[] = "214-Commands:\r\n214-HELO NOOP MAIL QUIT RCPT HELP DATA RSET\r\n214 End\r\n";
  56. static char banner[] = "220 %s SMTP ready\r\n";
  57. static char closing[] = "221 Closing\r\n";
  58. static char ok[] = "250 Ok\r\n";
  59. static char reset[] = "250 Reset state\r\n";
  60. static char sent[] = "250 Sent\r\n";
  61. static char ourname[] = "250 %s, Share and Enjoy!\r\n";
  62. static char enter[] = "354 Enter mail, end with .\r\n";
  63. static char ioerr[] = "452 Temp file write error\r\n";
  64. static char mboxerr[] = "452 Mailbox write error\r\n";
  65. static char badcmd[] = "500 Command unrecognized\r\n";
  66. static char syntax[] = "501 Syntax error\r\n";
  67. static char needrcpt[] = "503 Need RCPT (recipient)\r\n";
  68. static char unknown[] = "550 <%s> address unknown\r\n";
  69.  
  70. static struct tcb *smtp_tcb;
  71. /* Start up SMTP receiver service */
  72. smtp1(argc,argv)
  73. int argc;
  74. char *argv[];
  75. {
  76.     struct socket lsocket;
  77.     void r_mail(),s_mail();
  78.  
  79.     lsocket.address = ip_addr;
  80.     if(argc < 2)
  81.         lsocket.port = SMTP_PORT;
  82.     else
  83.         lsocket.port = atoi(argv[1]);
  84.  
  85.     smtp_tcb = open_tcp(&lsocket,NULLSOCK,
  86.         TCP_SERVER,0,r_mail,NULLVFP,s_mail,0,(char *)NULL);
  87. }
  88.  
  89. /* Shutdown SMTP service (existing connections are allowed to finish) */
  90. smtp0()
  91. {
  92.     if(smtp_tcb != NULLTCB)
  93.         close_tcp(smtp_tcb);
  94. }
  95.  
  96. /* SMTP connection state change upcall handler */
  97. static void
  98. s_mail(tcb,old,new)
  99. struct tcb *tcb;
  100. char old,new;
  101. {
  102.     struct mail *mp,*mail_create();
  103.  
  104.     switch(new){
  105. #ifdef    QUICKSTART
  106.     case SYN_RECEIVED:
  107. #else
  108.     case ESTABLISHED:
  109. #endif
  110.         if((mp = mail_create(tcb)) == NULLMAIL){
  111.             close_tcp(tcb);
  112.             break;
  113.         }
  114.         (void) tprintf(mp->tcb,banner,hostname);
  115.         log(tcb,"open SMTP");
  116.         break;        
  117.     case CLOSE_WAIT:
  118.         close_tcp(tcb);
  119.         break;
  120.     case CLOSED:
  121.         log(tcb,"close SMTP");
  122.         mp = (struct mail *)tcb->user;
  123.         mail_delete(mp);                
  124.         del_tcp(tcb);
  125.         /* Check if server is being shut down */
  126.         if(tcb == smtp_tcb)
  127.             smtp_tcb = NULLTCB;
  128.         break;
  129.     }
  130. }
  131.  
  132. /* SMTP receiver upcall handler */
  133. static void
  134. r_mail(tcb,cnt)
  135. struct tcb *tcb;
  136. int16 cnt;
  137. {
  138.     register struct mail *mp;
  139.     char c;
  140.     struct mbuf *bp;
  141.     char *inet_ntoa();
  142.     void docommand(),doline();
  143.  
  144.     if((mp = (struct mail *)tcb->user) == NULLMAIL){
  145.         /* Unknown session */
  146.         close_tcp(tcb);
  147.         return;
  148.     }
  149.     recv_tcp(tcb,&bp,cnt);
  150.     /* Assemble an input line in the session buffer.
  151.      * Return if incomplete
  152.      */
  153.     while(pullup(&bp,&c,1) == 1){
  154.         switch(c){
  155.         case '\r':    /* Strip cr's */
  156. #ifdef MSDOS
  157.         case '\032':    /* Strip ctrl/Z's */
  158. #endif
  159.             continue;
  160.         case '\n':    /* Complete line; process it */
  161.             mp->buf[mp->cnt] = '\0';
  162.             doline(mp);
  163.             break;
  164.         default:    /* Assemble line */
  165.             if(mp->cnt != LINELEN-1)
  166.                 mp->buf[mp->cnt++] = c;
  167.             break;
  168.         }
  169.     }
  170. }
  171. /* Process a line read on an SMTP connection (any state) */
  172. static void
  173. doline(mp)
  174. register struct mail *mp;
  175. {
  176.     void docommand(),deliver();
  177.  
  178.     switch(mp->state){
  179.     case COMMAND_STATE:
  180.         docommand(mp);
  181.         break;
  182.     case DATA_STATE:
  183.         tcp_output(mp->tcb);    /* Send ACK; disk I/O is slow */
  184.         if(mp->buf[0] == '.' && mp->buf[1] == '\0'){
  185.             mp->state = COMMAND_STATE;
  186.         /* Also sends appropriate response */
  187.             deliver(mp);
  188.             fclose(mp->data);
  189.             mp->data = NULLFILE;
  190.             del_list(mp->to);
  191.             mp->to = NULLLIST;
  192.             break;
  193.         }
  194.         /* for UNIX mail compatiblity */
  195.         if (strncmp(mp->buf,"From ",5) == 0)
  196.             (void) putc('>',mp->data);
  197.         /* Append to data file */
  198.         if(fprintf(mp->data,"%s\n",mp->buf) < 0){
  199.             mp->state = COMMAND_STATE;
  200.             (void) tprintf(mp->tcb,ioerr);
  201.         }
  202.         break;
  203.     }
  204.     mp->cnt = 0;
  205. }
  206. /* Create control block, initialize */
  207. static struct mail *
  208. mail_create(tcb)
  209. register struct tcb *tcb;
  210. {
  211.     register struct mail *mp;
  212.  
  213.     if((mp = (struct mail *)calloc(1,sizeof (struct mail))) == NULLMAIL)
  214.         return NULLMAIL;
  215.     mp->tcb = tcb;        /* Downward pointer */
  216.     tcb->user = (char *)mp;    /* Upward pointer */
  217.     return mp;
  218. }
  219.  
  220. /* Free resources, delete control block */
  221. static void
  222. mail_delete(mp)
  223. register struct mail *mp;
  224. {
  225.  
  226.     if (mp == NULLMAIL)
  227.         return;
  228.     if(mp->system != NULLCHAR)
  229.         free(mp->system);
  230.     if(mp->from != NULLCHAR)
  231.         free(mp->from);
  232.     if(mp->data != NULLFILE)
  233.         fclose(mp->data);
  234.     del_list(mp->to);
  235.     free((char *)mp);
  236. }
  237.  
  238. /* Parse and execute mail commands */
  239. static void
  240. docommand(mp)
  241. register struct mail *mp;
  242. {
  243.     register char **cmdp,*arg,*cp,*cmd;
  244.     struct list *ap;
  245.     FILE *tmpfile();
  246.     long t;
  247.     char address_type;
  248.  
  249.     cmd = mp->buf;
  250.     if(mp->cnt < 4){
  251.         /* Can't be a legal SMTP command */
  252.         (void) tprintf(mp->tcb,badcmd);
  253.         return;
  254.     }    
  255.     cmd = mp->buf;
  256.  
  257.     /* Translate entire buffer to lower case */
  258.     for(cp = cmd;*cp != '\0';cp++)
  259.         *cp = tolower(*cp);
  260.  
  261.     /* Find command in table; if not present, return syntax error */
  262.     for(cmdp = commands;*cmdp != NULLCHAR;cmdp++)
  263.         if(strncmp(*cmdp,cmd,strlen(*cmdp)) == 0)
  264.             break;
  265.     if(*cmdp == NULLCHAR){
  266.         (void) tprintf(mp->tcb,badcmd);
  267.         return;
  268.     }
  269.     arg = &cmd[strlen(*cmdp)];
  270.     /* Skip spaces after command */
  271.     while(*arg == ' ')
  272.         arg++;
  273.     /* Execute specific command */
  274.     switch(cmdp-commands){
  275.     case HELO_CMD:
  276.         if(mp->system != NULLCHAR)
  277.             free(mp->system);
  278.         if((mp->system = malloc((unsigned)strlen(arg)+1)) == NULLCHAR){
  279.             /* If the system is out of memory, just close */
  280.             close_tcp(mp->tcb);
  281.             break;            
  282.         } else {
  283.             strcpy(mp->system,arg);
  284.             (void) tprintf(mp->tcb,ourname,hostname);
  285.         }
  286.         break;
  287.     case NOOP_CMD:
  288.         (void) tprintf(mp->tcb,ok);
  289.         break;
  290.     case MAIL_CMD:
  291.         if(mp->from != NULLCHAR)
  292.             free(mp->from);
  293.         if((mp->from = malloc((unsigned)strlen(arg)+1)) == NULLCHAR){
  294.             /* If the system is out of memory, just close */
  295.             close_tcp(mp->tcb);
  296.             break;            
  297.         } else {
  298.             if((cp = getname(arg)) == NULLCHAR){
  299.                 (void) tprintf(mp->tcb,syntax);
  300.                 break;
  301.             }
  302.             strcpy(mp->from,cp);
  303.             (void) tprintf(mp->tcb,ok);
  304.         }
  305.         break;
  306.     case QUIT_CMD:
  307.         (void) tprintf(mp->tcb,closing);
  308.         close_tcp(mp->tcb);
  309.         break;
  310.     case RCPT_CMD:    /* Specify recipient */
  311.         if((cp = getname(arg)) == NULLCHAR){
  312.             (void) tprintf(mp->tcb,syntax);
  313.             break;
  314.         }
  315.  
  316.         /* check if address is ok */
  317.         if ((address_type = validate_address(cp)) == BADADDR) {
  318.             (void) tprintf(mp->tcb,unknown,cp);
  319.             break;
  320.         }
  321.         /* if a local address check for an alias */
  322.         if (address_type == LOCAL)
  323.             expandalias(&mp->to, cp);
  324.         else
  325.             /* a remote address is added to the list */
  326.             addlist(&mp->to, cp, address_type);
  327.  
  328.         (void) tprintf(mp->tcb,ok);
  329.         break;
  330.     case HELP_CMD:
  331.         (void) tprintf(mp->tcb,help);
  332.         break;
  333.     case DATA_CMD:
  334.         if(mp->to == NULLLIST){
  335.             (void) tprintf(mp->tcb,needrcpt);
  336.             break;
  337.         }
  338.         tcp_output(mp->tcb);    /* Send ACK; disk I/O is slow */
  339.         if((mp->data = tmpfile()) == NULLFILE){
  340.             (void) tprintf(mp->tcb,ioerr);
  341.             break;
  342.         }
  343.         /* Add timestamp; ptime adds newline */
  344.         time(&t);
  345.         fprintf(mp->data,"Received: ");
  346.         if(mp->system != NULLCHAR)
  347.             fprintf(mp->data,"from %s ",mp->system);
  348.         fprintf(mp->data,"by %s with SMTP\n\tid AA%ld ; %s",
  349.                 hostname, get_msgid(), ptime(&t));
  350.         if(ferror(mp->data)){
  351.             (void) tprintf(mp->tcb,ioerr);
  352.         } else {
  353.             mp->state = DATA_STATE;
  354.             (void) tprintf(mp->tcb,enter);
  355.         }
  356.         break;
  357.     case RSET_CMD:
  358.         del_list(mp->to);
  359.         mp->to = NULLLIST;
  360.         mp->state = COMMAND_STATE;
  361.         (void) tprintf(mp->tcb,reset);
  362.         break;
  363.     }
  364. }
  365. /* Given a string of the form <user@host>, extract the part inside the
  366.  * brackets and return a pointer to it.
  367.  */
  368. static
  369. char *
  370. getname(cp)
  371. register char *cp;
  372. {
  373.     register char *cp1;
  374.  
  375.     if((cp = index(cp,'<')) == NULLCHAR)
  376.         return NULLCHAR;
  377.     cp++;    /* cp -> first char of name */
  378.     if((cp1 = index(cp,'>')) == NULLCHAR)
  379.         return NULLCHAR;
  380.     *cp1 = '\0';
  381.     return cp;
  382. }
  383.  
  384. /* Deliver mail to the appropriate mail boxes and delete temp file */
  385. static
  386. void
  387. deliver(mp)
  388. register struct mail *mp;
  389. {
  390.     int ret;
  391.  
  392.     /* send to the rqueue */
  393.     if ((smtpmode & QUEUE) != 0) {
  394.         ret = router_queue(mp->tcb,mp->data,mp->from,mp->to);
  395.         if (ret != 0)
  396.             (void) tprintf(mp->tcb,ioerr);
  397.     } else {
  398.         ret = mailit(mp->tcb,mp->data,mp->from,mp->to);
  399.         if (ret != 0)
  400.             (void) tprintf(mp->tcb,mboxerr);
  401.     }
  402.     if (ret == 0)
  403.         (void) tprintf(mp->tcb,sent);
  404.         
  405. }
  406.  
  407. /* used to save local mail or reroute remote mail */
  408. mailit(tcb,data,from,to)
  409. struct tcb *tcb;
  410. FILE *data;
  411. char *from;
  412. struct list *to;
  413. {
  414.     register struct list *ap;
  415.     register FILE *fp;
  416.     int c;
  417. #ifdef MAC
  418.     char    mailbox[256],*logtime();
  419. #else
  420.     char    mailbox[50];
  421. #endif
  422.     char    *cp;
  423.     char    *desthost;
  424.     int    fail = 0;
  425. #ifndef MAC
  426.     time_t    t;
  427. #endif
  428.     for(ap = to;ap != NULLLIST;ap = ap->next) {
  429.  
  430.         fseek(data,0L,0);    /* rewind */
  431.  
  432.         /* non local mail queue it */
  433.         if (ap->type == DOMAIN) {
  434.             if ((desthost = index(ap->val,'@')) != NULLCHAR);
  435.                 desthost++;
  436.             fail = queuejob(tcb,data,desthost,ap->val,from);
  437.         } else {
  438.             /* strip off host name */
  439.             if ((cp = index(ap->val,'@')) != NULLCHAR)
  440.                 *cp = '\0';
  441.  
  442.             /* truncate long user names */
  443.             if (strlen(ap->val) > MBOXLEN)
  444.                 ap->val[MBOXLEN] = '\0';
  445.  
  446.             /* if mail file is busy save it in our smtp queue
  447.              * and let the smtp daemon try later.
  448.              */
  449.             if (mlock(mailspool,ap->val))
  450.                 fail = queuejob(tcb,data,hostname,ap->val,from);
  451.             else {
  452.                 sprintf(mailbox,"%s%c%s.txt",mailspool,PATH_DELIM,ap->val);
  453.                 if((fp = fopen(mailbox,"a+")) != NULLFILE) {
  454. #ifndef MAC
  455.                     time(&t);
  456. #endif
  457.                     fprintf(fp,
  458. #ifdef MAC
  459.                     "From %s %s\n",from,logtime());
  460. #else
  461.                     "From %s %s",from,ctime(&t));
  462. #endif
  463.                     while((c = getc(data)) != EOF)
  464.                         if(putc(c,fp) == EOF)
  465.                             break;
  466.                     if(ferror(fp))
  467.                         fail = 1;
  468.                     else
  469.                         fprintf(fp,"\n");
  470.                     /* Leave a blank line between msgs */
  471.                     fclose(fp);
  472. #ifdef MAC
  473.                     printf("\007New mail arrived for %s (%s)\n",
  474.                         ap->val,logtime());
  475. #else
  476.                     printf("New mail arrived for %s\n",ap->val);
  477. #endif
  478.                     fflush(stdout);
  479.                 } else 
  480.                     fail = 1;
  481.                 (void) rmlock(mailspool,ap->val);
  482.                 if (fail)
  483.                     break;
  484.                 log(tcb,
  485.                 "SMTP recv: To: %s From: %s",ap->val,from);
  486.             }
  487.         }
  488.     }
  489.     return(fail) ;
  490. }
  491.  
  492. /* Return Date/Time in Arpanet format in passed string */
  493. char *
  494. ptime(t)
  495. long *t;
  496. {
  497.     /* Print out the time and date field as
  498.      *        "DAY day MONTH year hh:mm:ss ZONE"
  499.      */
  500.     register struct tm *ltm;
  501.     static char tz[4];
  502.     static char str[40];
  503.     extern char *getenv();
  504.     extern struct tm *localtime();
  505.     char *p;
  506.     static char *days[7] = {
  507.     "Sun","Mon","Tue","Wed","Thu","Fri","Sat" };
  508.  
  509.     static char *months[12] = {
  510.         "Jan","Feb","Mar","Apr","May","Jun",
  511.         "Jul","Aug","Sep","Oct","Nov","Dec" };
  512.  
  513.     /* Read the system time */
  514.     ltm = localtime(t);
  515.  
  516.     if (*tz == '\0')
  517.         if ((p = getenv("TZ")) == NULL)
  518.             strcpy(tz,"GMT");
  519.         else
  520.             strncpy(tz,p,3);
  521.  
  522.     /* rfc 822 format */
  523.     sprintf(str,"%s, %.2d %s %02d %02d:%02d:%02d %.3s\n",
  524.         days[ltm->tm_wday],
  525.         ltm->tm_mday,
  526.         months[ltm->tm_mon],
  527.         ltm->tm_year,
  528.         ltm->tm_hour,
  529.         ltm->tm_min,
  530.         ltm->tm_sec,
  531.         tz);
  532.     return(str);
  533. }
  534.  
  535. long 
  536. get_msgid()
  537. {
  538.     char sfilename[LINELEN];
  539.     char s[20];
  540.     register long sequence = 0;
  541.     FILE *sfile;
  542.     long atol();
  543.  
  544.     sprintf(sfilename,"%s%csequence.seq",mailqdir,PATH_DELIM);
  545.     sfile = fopen(sfilename,"r");
  546.  
  547.     /* if sequence file exists, get the value, otherwise set it */
  548.     if (sfile != NULL) {
  549.         (void) fgets(s,sizeof(s),sfile);
  550.         sequence = atol(s);
  551.     /* Keep it in range of and 8 digit number to use for dos name prefix. */
  552.         if (sequence < 0L || sequence > 99999999L )
  553.             sequence = 0;
  554.         fclose(sfile);
  555.     }
  556.  
  557.     /* increment sequence number, and write to sequence file */
  558.     sfile = fopen(sfilename,"w");
  559.     fprintf(sfile,"%ld",++sequence);
  560.     fclose(sfile);
  561.     return sequence;
  562. }
  563.  
  564. #ifdef    MSDOS
  565. /* Illegal characters in a DOS filename */
  566. static char baddoschars[] = "\"[]:|<>+=;,";
  567. #endif
  568.  
  569. /* test if mail address is valid */
  570. int
  571. validate_address(s)
  572. char *s;
  573. {
  574.     FILE *fp;
  575.     char *cp;
  576.     int32 addr;
  577.     char    address_type;
  578.     int32 mailroute();
  579.  
  580.  
  581.  
  582.     /* if address has @ in it the check dest address */
  583.     if ((cp = index(s,'@')) != NULLCHAR) {
  584.         cp++;
  585.         /* 1st check if its our hostname
  586.         * if not then check the hosts file and see
  587.         * if we can resolve ther address to a know site
  588.         * or one of our aliases
  589.         */
  590.         if (strcmp(cp,hostname) != 0) {
  591.             if ((addr = mailroute(cp)) == 0
  592.                 && (smtpmode & QUEUE) == 0)
  593.                 return BADADDR;
  594.             if (addr != ip_addr)
  595.                 return DOMAIN;
  596.         }
  597.         
  598.         /* on a local address remove the host name part */
  599.         *--cp = '\0';
  600.     }
  601.  
  602.     /* if using an external router leave address alone */
  603.     if ((smtpmode & QUEUE) != 0)
  604.         return LOCAL;
  605.  
  606.  
  607.     /* check for the user%host hack */
  608.     if ((cp = index(s,'%')) != NULLCHAR) {
  609.         *cp = '@';
  610.         cp++;
  611.         /* reroute based on host name following the % seperator */
  612.         if (mailroute(cp) == 0)
  613.             return BADADDR;
  614.         else
  615.             return DOMAIN;
  616.     }
  617.     address_type = LOCAL;
  618.  
  619. #ifdef MSDOS    /* dos file name checks */
  620.     /* Check for characters illegal in MS-DOS file names */
  621.     for(cp = baddoschars;*cp != '\0';cp++){
  622.         if(index(s,*cp) != NULLCHAR)
  623.             return BADADDR;    
  624.     }
  625. #endif
  626.     return LOCAL;
  627. }
  628.  
  629. /* place a mail job in the outbound queue */
  630. int
  631. queuejob(tcb,dfile,host,to,from)
  632. struct tcb *tcb;
  633. FILE *dfile;
  634. char *host,*to,*from;
  635. {
  636.     FILE *fp;
  637. #ifdef MAC
  638.     char tmpstring[256];
  639. #else
  640.     char tmpstring[50];
  641. #endif
  642.     char prefix[9];
  643.     register int c;
  644.  
  645.     sprintf(prefix,"%ld",get_msgid());
  646.     log(tcb,"SMTP queue job %s To: %s From: %s",prefix,to,from);
  647.     mlock(mailqdir,prefix);
  648.     sprintf(tmpstring,"%s%c%s.txt",mailqdir,PATH_DELIM,prefix);
  649.     if((fp = fopen(tmpstring,"w")) == NULLFILE) {
  650.         (void) rmlock(mailqdir,prefix);
  651.         return 1;
  652.     }
  653.     while((c = getc(dfile)) != EOF)
  654.         if(putc(c,fp) == EOF)
  655.             break;
  656.     if(ferror(fp)){
  657.         fclose(fp);
  658.         (void) rmlock(mailqdir,prefix);
  659.         return 1;
  660.     }
  661.     fclose(fp);
  662.     sprintf(tmpstring,"%s%c%s.wrk",mailqdir,PATH_DELIM,prefix);
  663.     if((fp = fopen(tmpstring,"w")) == NULLFILE) {
  664.         (void) rmlock(mailqdir,prefix);
  665.         return 1;
  666.     }
  667.     fprintf(fp,"%s\n%s\n%s\n",host,from,to);
  668.     fclose(fp);
  669.     (void) rmlock(mailqdir,prefix);
  670.     return 0;
  671. }
  672.  
  673. /* Deliver mail to the appropriate mail boxes */
  674. int
  675. router_queue(tcb,data,from,to)
  676. struct tcb *tcb;
  677. FILE *data;
  678. char *from;
  679. struct list *to;
  680. {
  681.     int c;
  682.     register struct list *ap;
  683.     FILE *fp;
  684. #ifdef MAC
  685.     char tmpstring[256];
  686. #else
  687.     char tmpstring[50];
  688. #endif
  689.     char prefix[9];
  690.  
  691.     sprintf(prefix,"%ld",get_msgid());
  692.     mlock(routeqdir,prefix);
  693.     sprintf(tmpstring,"%s%c%s.txt",routeqdir,PATH_DELIM,prefix);
  694.     if((fp = fopen(tmpstring,"w")) == NULLFILE) {
  695.         (void) rmlock(routeqdir,prefix);
  696.         return 1;
  697.     }
  698.     fseek(data,0L,0);    /* rewind */
  699.     while((c = getc(data)) != EOF)
  700.         if(putc(c,fp) == EOF)
  701.             break;
  702.     if(ferror(fp)){
  703.         fclose(fp);
  704.         (void) rmlock(routeqdir,prefix);
  705.         return 1;
  706.     }
  707.     fclose(fp);
  708.     sprintf(tmpstring,"%s%c%s.wrk",routeqdir,PATH_DELIM,prefix);
  709.     if((fp = fopen(tmpstring,"w")) == NULLFILE) {
  710.         (void) rmlock(routeqdir,prefix);
  711.         return 1;
  712.     }
  713.     fprintf(fp,"From: %s\n",from);
  714.     for(ap = to;ap != NULLLIST;ap = ap->next) {
  715.         fprintf(fp,"To: %s\n",ap->val);
  716.     }
  717.     fclose(fp);
  718.     (void) rmlock(routeqdir,prefix);
  719.     log(tcb,"SMTP rqueue job %s From: %s",prefix,from);
  720.     return 0;
  721. }
  722.  
  723. /* add an element to the front of the list pointed to by head 
  724. ** return NULLLIST if out of memory.
  725. */
  726. struct list *
  727. addlist(head,val,type)
  728. struct list **head;
  729. char *val;
  730. int type;
  731. {
  732.     register struct list *tp;
  733.  
  734.     tp = (struct list *)calloc(1,sizeof(struct list));
  735.     if (tp == NULLLIST)
  736.         return NULLLIST;
  737.  
  738.     tp->next = NULLLIST;
  739.  
  740.     /* allocate storage for the char string */
  741.     if ((tp->val = malloc((unsigned)strlen(val)+1)) == NULLCHAR) {
  742.         (void) free((char *)tp);
  743.         return NULLLIST;
  744.     }
  745.     strcpy(tp->val,val);
  746.     tp->type = type;
  747.  
  748.     /* add entry to front of existing list */
  749.     if (*head == NULLLIST)
  750.         *head = tp;
  751.     else {
  752.         tp->next = *head;
  753.         *head = tp;
  754.     }
  755.     return tp;
  756.  
  757. }
  758.  
  759. #define SKIPWORD(X) while(*X && *X!=' ' && *X!='\t' && *X!='\n' && *X!= ',') X++;
  760. #define SKIPSPACE(X) while(*X ==' ' || *X =='\t' || *X =='\n' || *X == ',') X++;
  761.  
  762. /* check for and alias and expand alias into a address list */
  763. struct list *
  764. expandalias(head, user)
  765. struct list **head;
  766. char *user;
  767. {
  768.     FILE *fp;
  769.     register char *s,*p,*h;
  770.     int inalias;
  771.     struct list *tp;
  772.     char buf[LINELEN];
  773.     
  774.     
  775.         /* no alias file found */
  776.     if ((fp = fopen(alias, "r")) == NULLFILE)
  777.         return addlist(head, user, LOCAL);
  778.  
  779.     inalias = 0;
  780.     while (fgets(buf,LINELEN,fp) != NULLCHAR) {
  781.         p = buf;
  782.         if ( *p == '#' || *p == '\0')
  783.             continue;
  784.         rip(p);
  785.  
  786.         /* if not in an matching entry skip continuation lines */
  787.         if (!inalias && isspace(*p))
  788.             continue;
  789.  
  790.         /* when processing an active alias check for a continuation */
  791.         if (inalias) {
  792.             if (!isspace(*p)) 
  793.                 break;    /* done */
  794.         } else {
  795.             s = p;
  796.             SKIPWORD(p);
  797.             *p++ = '\0';    /* end the alias name */
  798.             if (strcmp(s,user) != 0)
  799.                 continue;    /* no match go on */
  800.             inalias = 1;
  801.         }
  802.  
  803.         /* process the recipients on the alias line */
  804.         SKIPSPACE(p);
  805.         while(*p != '\0' && *p != '#') {
  806.             s = p;
  807.             SKIPWORD(p);
  808.             if (*p != '\0')
  809.                 *p++ = '\0';
  810.  
  811.             /* find hostname */
  812.             if ((h = index(s,'@')) != NULLCHAR)
  813.                 tp = addlist(head,s,DOMAIN);
  814.             else
  815.                 tp = addlist(head,s,LOCAL);
  816.             SKIPSPACE(p);
  817.         }
  818.     }
  819.     (void) fclose(fp);
  820.  
  821.     if (inalias)    /* found and processed and alias. */
  822.         return tp;
  823.  
  824.     /* no alias found treat as a local address */
  825.     return addlist(head, user, LOCAL);
  826. }
  827.  
  828.